from multiprocessing.pool import ThreadPool as Pool
from src.SNMP_proto import SNMP_proto
from sys import exc_info
from src.trigger import trigger_coiled, trigger_single, trigger_close
from public.logger import getLogger
import threading
import queue
import time
from config.config import IP_F
from config.config import trigger_iface,trigger_multiip,trigger_multiport,trigger_test,master_ip
import src.bos as udp_parse


class IOC_opr():
    def __init__(self, data_list, data_node,index_dict, host_dict, name_dict):
        print("IOC Opr 初始化")
        self.data_list = data_list
        self.host_dict = host_dict
        self.index_dict = index_dict
        self.name_dict = name_dict
        self.data_node = data_node
        self.pool = None
        self.logger={}
        for data in set(self.name_dict.values()):
            # print(self.name_dict.values())
            self.logger[data] = getLogger(data)
        self.logger['WR']=getLogger('WR')
        self.delay = {}
        self.width = {}
        self.enable = {}
        self.sync_status = {}
        self.time_sys = {}
        self.time_run = {}
        self.temperature = {}
        self.rtt = {}
        self.portlinkstatus={}
        self.trigger_value = 1
        self.state_value = 0
        self._E_Flag = False
        self.timestamp_cache = {}
        self.enable_cache = {}
        self.heartbeat_enable = {}
        self.interlock_enable = {}
        self.bypass_states = {name: 0 for name in self.name_dict.keys()}
        # 初始化 SNMP 操作类
        self.SNMP = SNMP_proto(
            data_list=self.data_list,
            host_dict=self.host_dict,
            index_dict=self.index_dict,
            name_dict=self.name_dict
        )
        # 读取数据并更新属性
        snmp_data = self.SNMP.init_snmp()
        self.delay.update(snmp_data["delay"])
        self.width.update(snmp_data["width"])
        self.enable.update(snmp_data["enable"])
        self.sync_status.update(snmp_data["sync_status"])
        self.time_sys.update(snmp_data["time_sys"])
        self.time_run.update(snmp_data["time_run"])
        self.temperature.update(snmp_data["temperature"])
        self.rtt.update(snmp_data["rtt"])
        self.portlinkstatus.update(snmp_data["portlinkstatus"])

        self.heartbeat_enable.update(snmp_data["heartbeat_enable"])
        self.interlock_enable.update(snmp_data["interlock_enable"])
        # print("init:", self.delay, self.width, self.enable)

        # 初始化线程池
        # print(self.data_list,len(self.data_list))
        self.pool = Pool(processes=len(self.data_list)+len(self.data_node))
        
        # 启动状态监测线程
        self.monitor_thread = threading.Thread(target=self.monitor_status)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
        print("IOC_Opr 初始化完成")
    # 进行 PV 的初始化或更新操作
    def get_init_pvname(self, dbl):
        self.dbl = dbl
        self.PRF = dbl[0]
        self.Ctrl = dbl[1]
        self.Trigger = dbl[2]
        self.Trigger_State = dbl[3]
        print("获取DataBase List 中")

    def get_function_list(self, getParam, setParam, updatePVs, callbackPV):
        self.getParam = getParam
        self.setParam = setParam
        self.updatePVs = updatePVs
        self.callbackPV = callbackPV
        status_data = self.SNMP.status_monitor()
        self.initialize_pv(status_data)
    def monitor_status(self):
        while True:
            
            status_data = self.SNMP.status_monitor()
            self.update_status_pv(status_data)
            time.sleep(40)  # 根据需要调整更新频率

    def update_status_pv(self, status_data):
        # 更新各个status PV 的值
        for pvname, status in status_data['sync_status'].items():
            self.sync_status[pvname] = status
            self.setParam(pvname + "_SyncStatus", status)  # 更新 PV
            # print(pvname + "_SyncStatus", status)

        for pvname, time_value in status_data['time_sys'].items():
            self.time_sys[pvname] = time_value
            self.setParam(pvname + "_SystemTime", time_value)  # 更新 PV
             # self.setParam(f"{pvname}_SystemTime", time_value)  # 更新 PV

        for pvname, uptime in status_data['time_run'].items():
            self.time_run[pvname] = uptime
            self.setParam(pvname + "_RunTime", uptime)  # 更新 PV
            # self.setParam(f"{pvname}_RunTime", uptime)  # 更新 PV
        # print(status_data['temperature'].items())
        for pvname, temp in status_data['temperature'].items():
            self.temperature[pvname] = temp
            self.setParam(pvname + "_Temperature", temp)
            # print(pvname + "_Temperature", temp)
            # self.setParam(f"{pvname}_Temperature", temp)  # 更新 PV

        for pvname, rtt_value in status_data['rtt'].items():
            self.rtt[pvname] = rtt_value
            self.setParam(pvname + "_RTT", rtt_value)
            # self.setParam(f"{pvname}_RTT", rtt_value)  # 更新 PV
        for pvname, portlinkstatus_value in status_data['portlinkstatus'].items():
            self.portlinkstatus[pvname] = portlinkstatus_value
            self.setParam(pvname + "_PortLinkStatus", portlinkstatus_value)
    def initialize_pv(self,status_data):
        print("初始化PV开始")
        self.setParam("TIMS:WR:Init_State",0)
        for key in self.delay.keys():
            
            self.setParam(reason=key + "_D", value=self.delay[key])
            self.setParam(reason=key + "_W", value=self.width[key])
            self.setParam(reason=key + "_Enable", value=self.enable[key])
            self.update_Wave_pv(key)
        for pvname,value in self.heartbeat_enable.items():
            self.setParam(reason=pvname + ":HeartBeat_Enable", value=value)

        
        for pvname,value in self.interlock_enable.items():
            self.setParam(pvname + ":InterLock", 1 if value == 0 else 0)
            self.setParam(pvname + ":InterLock_L", 1 if value == 0 else 0)
            
        self.update_status_pv(status_data)
        print("初始化PV完成")
        self.setParam("TIMS:WR:Init_State",1)
        self.updatePVs()
    def handle_read(self, reason):
        try:
            if reason == "TIMS:WR:Reset_Bos":
                _inter_Flag = True
                interlock = self.SNMP.get_interlock(master_ip,device = "Master")
                if interlock == 0 or interlock == -1:
                    _inter_Flag = False
                for pvname,host in self.host_dict.items():
                    if host == master_ip:
                        continue
                    interlock = self.SNMP.get_interlock(host,device = "Node")
                    #print(f"host:{host},interlock:{interlock}")
                    self.setParam(pvname+":InterLock",interlock)
                    if interlock == 0:
                        self.setParam(pvname+":InterLock_L",0)
                        _inter_Flag = False
                if _inter_Flag:
                    # state_value = self.handle_trigger(self.trigger_value)
                    self.setParam("TIMS:WR:Enable_Bos",1)
            for pvname,host in self.host_dict.items():
                UTC_Time_String = self.SNMP.get_UTC(host)
                self.setParam(pvname+":Timestamp_UTC",UTC_Time_String)
            self.updatePVs()
        except:
            pass
    def handle_write(self, reason, value):
        # 检查触发操作
        if reason == self.Trigger:
            # 处理触发操作
            state_value = self.handle_trigger(value)
            if state_value == 1:  # 假设 1 表示触发操作成功
                # 触发操作成功，执行实际的写操作
                self.setParam(reason=self.Trigger_State, value=state_value)
                self.setParam(reason=reason, value=value)
                # self.logger[data["name"]].debug("Trigger operation successed!")
                self.logger["WR"].debug("Trigger operation successed!")
                # for data in self.data_list:
                #     for key in data["data"].keys():
                #         self.update_Wave_pv(key)
                # return True
            else:
                # 触发操作失败
                # self.logger[data["name"]].debug(f"Trigger operation failed!")
                # self.logger['WR'].debug(f"Trigger operation failed!")
                self.setParam(reason=self.Trigger_State, value=0)
                return False
        # 检查是否需要设置初始化参数
        if value == self.getParam(reason=reason):
            return True
        # 初始化 PV
        # self.initialize_pv()
        # 默认操作状态为失败
        status = False
        # 根据不同的 PV 名称执行相应操作
        if reason == self.Ctrl:
            # self.SNMP.save()
            status = True
        elif reason == "TIMS:WR:Reset_Bos":
            for pvname in self.host_dict.keys():
                value = self.getParam(reason=pvname+":InterLock")
                self.setParam(reason=pvname+":InterLock_L",value=value)
            self.SNMP.reset()
        elif reason == self.PRF:
            if value == 0:
                print("FREQ can't set 0")
                return status
            else:
                self.setParam(reason, value)
                status = self.Operation(opr_type="frequency")
        elif "HeartBeat_Enable" == reason[-16:]:
            self.setParam(reason, value)
            time.sleep(0.05)
            status = self.SNMP.heartbeat_enable(reason[0:-17],value=value)
        elif reason[-7:] == "_Enable":
            self.setParam(reason, value)
            time.sleep(0.05)
            status = self.Operation(pvname=reason[:-7])
        elif reason[-2:] == "_W":
            FREQ = self.getParam(self.PRF)
            # D_us = self.getParam(reason[:-2]+"_W")
            # T_us = (1/FREQ)*10**6
            self.setParam(reason, value)
            self.width[reason[:-2]] = value
            status = self.Operation(pvname=reason[:-2])
            self.update_Wave_pv(reason[:-2])
            # if value > (T_us-D_us):
            #     print("Width can't set more than (Period-Delay)")
            #     return status
            # else:
            #     self.setParam(reason, value)
            #     self.width[reason[:-2]] = value
            #     status = self.Operation(pvname=reason[:-2])
            #     self.update_Wave_pv(reason[:-2])

        elif reason[-2:] == "_D":
            FREQ = self.getParam(self.PRF)
            # W_us = self.getParam(reason[:-2]+"_W")
            # T_us = (1/FREQ)*10**6
            self.setParam(reason, value)
            self.delay[reason[:-2]] = value
            status = self.Operation(pvname=reason[:-2])
            self.update_Wave_pv(reason[:-2])
            # if value > (T_us-W_us):
            #     print("Delay can't set more than (Period-Width)")
            #     return status
            # elif value > 100000:
            #     print("Delay can't set more than 100ms")
            #     return status
            # else:
            #     self.setParam(reason, value)
            #     self.delay[reason[:-2]] = value
            #     status = self.Operation(pvname=reason[:-2])
            #     self.update_Wave_pv(reason[:-2])
        return status

    def Operation(self, opr_type=None, pvname=None):
        self.updatePVs()
        
        try:
            if opr_type == "frequency":
                # start_time = time()
                for data in self.data_list:
                    ret = self.pool.apply_async(
                        self.FRQ_Set, args=(data,))
                for pvname in self.data_node.keys():
                    ret = self.pool.apply_async(
                        self.node_FRQ_Set, args=(pvname,))
                #time.sleep(1)
            else:
                strat_time = time.time()
                FREQ = self.getParam(self.PRF)
                Width_us = self.getParam(pvname+"_W")
                Delay_us = self.getParam(pvname+"_D")
                Enable = self.getParam(pvname+"_Enable")
                self.logger[self.name_dict[pvname]].debug(
                    "Debug: Run : ", pvname, " index : ", self.index_dict[pvname])
                
                enable,width,delay=self.SNMP.SNMP_opr(
                    pvname=pvname, FREQ=FREQ, Width_us=Width_us, Delay_us=Delay_us, Enable=Enable)
                self.logger["WR"].debug("Trigger operation successed!")
                self.setParam(pvname+"_Enable",value=enable)
                self.setParam(pvname+"_W",value=width)
                self.setParam(pvname+"_D",value=delay)
                self.SNMP.save(pvname=pvname,host=self.host_dict[pvname])
                end_time = time.time()-strat_time
                self.logger[self.name_dict[pvname]].debug("Debug: Finish ,use time is {}\n".format(end_time))
            
        except OSError:
            self.logger[self.name_dict[pvname]].error(
                'ERROR', str(exc_info()[1]))
            return False
        for reason in self.dbl:
            self.callbackPV(reason)
            self.callbackPV(reason)
        self.updatePVs()
        state_value = self.handle_trigger(self.trigger_value)
        return True
    # 触发逻辑

    def handle_trigger(self,value):
        trigger_functions = {
            0: trigger_close,   # 关闭触发
            1: trigger_coiled,  # 连续触发
            2: trigger_single   # 单触发
        }
        self.trigger_value = value
        if value in trigger_functions:  # 检查值是否在有效的触发类型中
            # # 启动触发线程
            trigger_thread = threading.Thread(target=trigger_functions[value])
            trigger_thread.start()
            # # 等待线程结束
            trigger_thread.join(timeout=0.2)
            time.sleep(1)
            # status=self.SNMP.Trigger_Status(pvname=trigger_test)
            # # print("status:",status,type(status))
            # # print("inputvalue:",value,type(value))
            # if (status=="1" and value==0)or (status=="11" and value==1)or (status=="10" and value==2):
            #     status_value=1
             
            # else:
            #     status_value=0
          
               
            # return status_value
            # 创建一个停止事件
            # stop_event = threading.Event()
            # result_queue = queue.Queue()

            # # 启动多播接收线程
            # multicast_ip = trigger_multiip  # 替换为你的多播地址
            # multicast_port = trigger_multiport # 多播端口
            # iface = trigger_iface  # 替换为你的网络接口
            # sniff_thread = threading.Thread(target=sniff_multicast_packets, args=(
            #     multicast_ip, multicast_port, iface, stop_event, result_queue))
            # sniff_thread.start()

            # # 启动触发线程
            # trigger_thread = threading.Thread(target=trigger_functions[value])
            # trigger_thread.start()

            # # 等待线程结束
            # trigger_thread.join(timeout=1)
            # sniff_thread.join(timeout=1)

            # # 更新 Trigger_State 对应的 PV
            # if not result_queue.empty():
            #     state_value = result_queue.get()
            # else:
            #     state_value = 0
            # return state_value
            # 根据状态值更新触发值
    # 更新波形

    def update_Wave_pv(self, pvname):
        TOTAL_POINTS = 2000
        CYCLES = 2
        POINTS_PER_CYCLE = TOTAL_POINTS // CYCLES

        self.Wave_pv = [2 * self.index_dict[pvname]] * TOTAL_POINTS

        delay_us = self.delay.get(pvname, 0)
        width_us = self.width.get(pvname, 0)

        # total_us = delay_us + width_us
        # if total_us > 1000000:
        #     raise ValueError("Total of delay and width exceeds the maximum allowed range (1000000 us).")

        if width_us == 1000000:
            high_value = 1 + 2 * self.index_dict[pvname]  # High level value
            self.Wave_pv = [high_value] * TOTAL_POINTS
        else:
            # Get default value if key does not exist
            delay_points = self.map_to_points_d(self.delay.get(pvname, 0))
            width_points = self.map_to_points_w(self.width.get(pvname, 0))

            if self.trigger_value == 0:  # CLOSE
                self.setParam(pvname + "_Wave", self.Wave_pv)
                self.updatePVs()
                return

            high_value = 1 + 2 * self.index_dict[pvname]  # High level value

            if self.trigger_value == 1:  # AC 连续触发
                for cycle in range(CYCLES):
                    start_idx = cycle * POINTS_PER_CYCLE
                    for i in range(start_idx + delay_points, start_idx + delay_points + width_points):
                        if i < (cycle + 1) * POINTS_PER_CYCLE:
                            self.Wave_pv[i] = high_value

            elif self.trigger_value == 2:  # VME 单次触发
                for i in range(delay_points, delay_points + width_points):
                    if i < POINTS_PER_CYCLE:
                        self.Wave_pv[i] = high_value

        self.setParam(pvname + "_Wave", self.Wave_pv)
        self.updatePVs()

    def FRQ_Set(self, data):
        """ 设置频率 """
        for pv in data["data"].keys():
            self.Operation(pvname=pv)
            
    def node_FRQ_Set(self, pvname):
        """ 设置频率 """
        self.Operation(pvname=pvname)
        

    def map_to_points_w(self, value):
        if value <= 10:
            return int(value * 10)
        elif value <= 100:
            return int(100 + (value - 10) / 90 * 100)
        elif value <= 1000:
            return int(200 + (value - 100) / 900 * 100)
        elif value <= 10000:
            return int(300 + (value - 1000) / 9000 * 100)
        elif value <= 100000:
            return int(400 + (value - 10000) / 90000 * 100)
        else:
            return int(500 + (value - 100000) / 900000 * 100)

    def map_to_points_d(self, value):
        if value <= 10:
            return int(value * 10)
        elif value <= 1000:
            return int(100 + (value - 100) / 900 * 100)
        elif value <= 10000:
            return int(200 + (value - 1000) / 9000 * 100)
        else:
            return int(300 + (value - 10000) / 90000 * 100)
